module Smurf
  class Stylesheet
    def self.minifies?(paths) !paths.grep(%r[\.css(\?\d+)?$]).empty?; end

    def initialize(content)
      @content = content.nil? ? nil : minify(content)
    end
    
    def minified; @content; end

    # TODO: deal with string values better (urls, content blocks, etc.)
    def minify(content)
      class << content
        include Minifier
        include ImageTimestamp
      end
      content.append_timestamp_to_image_url.compress_whitespace.remove_comments.remove_spaces_outside_block.
        remove_spaces_inside_block.trim_last_semicolon.strip
    end

    module Minifier
      # .*? is a non-greedy match on anything
      def compress_whitespace; compress!(/\s+/, ' '); end
      def remove_comments; compress!(/\/\*.*?\*\/\s?/, ''); end
      def remove_spaces_outside_block
        compress!(/(\A|\})(.*?)\{/) { |m| m.gsub(/\s?([}{,])\s?/, '\1') }
      end
      def remove_spaces_inside_block
        compress!(/\{(.*?)(?=\})/) do |m|
          # remove spaces in the labels/attributes
          m.gsub(/(?:\A|\s*;)(.*?)(?::\s*|\z)/) { |n| n.gsub(/\s/, '') }.strip
        end
      end
      def trim_last_semicolon; compress!(/;(?=\})/, ''); end
    private
      def compress!(*args, &block) gsub!(*args, &block) || self; end
    end
    
    # covert image url to versioned param with file timestamp.
    module ImageTimestamp
      def append_timestamp_to_image_url
        self.gsub!(/url\((['"]*)(.+)(['"]*)\)/) do
          open, file, close = $1, $2, $3
          if file[file.length - 1,1] == "'"
            file = file.gsub!("'","")
            close = "'#{close}"
          elsif file[file.length - 1,1] == '"'
            file = file.gsub!("\"","")
            close = "\"#{close}"
          end

          timestamp = ""
          css_dir = File.join(Rails.root,"public/stylesheets")
          if file =~ /.\.(ico|css|js|gif|jpe?g|png)/
            FileUtils.cd(css_dir) do
              f = nil
              if file =~ /^\// # absolute path
                real_file = "#{Rails.root}/public#{file}"
                f = File.new(real_file) if File.exist?(real_file)                
              else # relative path
                f = File.new(file) if File.exist?(file)    
              end
              if !f.blank?
                timestamp = "?#{f.mtime.to_i.to_s}" 
              end
            end
          end
          
          "url(#{open}#{file}#{timestamp}#{close})"
        end || self
      end
    end 
    
  end # Stylesheet
end # Smurf
